/**
 * @description 子游戏热更
 * @date 2024.9.10
 * @author wz
 * @midify 2024.9.10
 * @editor wz
 */

import { _decorator, AssetManager, assetManager, SceneAsset } from 'cc';
import { Singleton } from '../../utils/Singleton';
import { VersionUtils } from '../../utils/VersionUtil';

export enum SubGameBundleState {
    NONE,

    /**
     * bundle更新
     */
    UPDATE_BUNDLE,

    /**
     * bundle更新失败
     */
    UPDATE_BUNDLE_FAIL,

    /**
     * 场景更新
     */
    UPDATE_SCENE,

    /**
     * 场景更新失败
     */
    UPDATE_SCENE_FAIL,
}

/**
 * 加载中回调
 */
export type SubGameUpdateCallback = (gameId: number, percent: number) => void

/**
 * 加载完成回调
 */
export type SubGameFinishCallback = (gameId: number, scene: SceneAsset) => void

/**
 * 子游戏bundle信息
 */
export class SubGameBundleInfo {
    constructor(gameId: number) {
        this.url = '';
        this.gameId = gameId;
        this.state = SubGameBundleState.NONE;
        this.percent = 0;
        this.version = '';
        this.bundle = null;
        this.callback_updates = [];
        this.callback_finishs = [];
    }

    /**
     * 地址
     */
    url: string = '';

    /**
     * bundle名字
     */
    gameId: number = 0;

    /**
     * 更新状态
     */
    state: SubGameBundleState = SubGameBundleState.NONE;

    /**
     * 更新进度
     */
    percent: number = 0;

    /**
     * bundle版本
     */
    version: string = '';

    /**
     * bundle包
     */
    bundle: AssetManager.Bundle = null;

    /**
     * 更新进度回调
     */
    callback_updates: SubGameUpdateCallback[] = null;

    /**
     * 加载完成回调
     */
    callback_finishs: SubGameFinishCallback[] = null;
}

export class SubMgr extends Singleton {
    /**
     * bundle存储名前缀
     */
    readonly bundleStorageName = "bundle_storage_name_";

    /**
     * 本地版本号
     */
    readonly package_version = "1.1.0";

    /**
     * 子游戏bundle信息
     */
    private bundleMap: Map<number, SubGameBundleInfo> = new Map();

    /**
     * 获取子游戏bundle版本
     * @param gameId 
     * @returns 
     */
    getLocalVersion(gameId: number): string {
        let version = localStorage.getItem(this.bundleStorageName + gameId)
        return version || this.package_version;
    }

    /**
     * 设置子游戏bundle版本
     * @param gameId 
     * @param version 
     */
    private setLocalVersion(gameId: number, version: string) {
        localStorage.setItem(this.bundleStorageName + gameId, version)
    }

    /**
     * 版本比较
     * @param local_version 
     * @param server_version 
     * @returns 
     */
    private compareVersion(local_version: string, server_version: string): boolean {
        return VersionUtils.toVerNumber(local_version) < VersionUtils.toVerNumber(server_version)
    }

    /**
     * 获取bundle信息
     * @param gameId 
     * @returns 
     */
    private getBundleInfo(gameId: number): SubGameBundleInfo {
        let info = this.bundleMap.get(gameId);
        if (!info) {
            info = new SubGameBundleInfo(gameId);
            info.version = this.getLocalVersion(gameId);
            this.bundleMap.set(gameId, info);
        }
        return info;
    }

    /**
     * 加载bundle
     * @param info
     * @param server_version 
     * @returns 
     */
    private async loadSubGameBundle(info: SubGameBundleInfo, server_version: string) {
        return new Promise<SubGameBundleInfo>((resolve, reject) => {
            if (info.state == SubGameBundleState.NONE && this.compareVersion(info.version, server_version)) {
                info.state = SubGameBundleState.UPDATE_BUNDLE
                assetManager.loadBundle(info.url + info.gameId, (err, bundle) => {
                    if (!err) {
                        info.state = SubGameBundleState.UPDATE_SCENE
                        info.bundle = bundle
                        info.version = server_version
                        resolve(info);
                    }
                    else {
                        info.state = SubGameBundleState.UPDATE_BUNDLE_FAIL
                        info.callback_updates.length = 0
                        info.callback_finishs.length = 0
                        console.error("load bundle error:", err);
                        reject();
                    }
                });
            }
            else resolve(info)
        })
    }


    /**
     * 检查是否更新
     * @param gameId 
     * @param server_version 
     * @returns 
     */
    checkUpdate(gameId: number, server_version: string) {
        return this.compareVersion(this.getLocalVersion(gameId), server_version)
    }

    /**
     * 加载场景
     * @param url (http://sup.qqwlsq.com/1.1.1/1001/search_100/)
     * @param gameId 
     * @param server_version 
     */
    async loadSubGameScene(url: string, gameId: number, server_version: string, callback_update?: SubGameUpdateCallback, callback_finish?: SubGameFinishCallback) {
        let info = this.getBundleInfo(gameId)
        info.url = url;
        //保存回调
        if (callback_update) info.callback_updates.push(callback_update)
        if (callback_finish) info.callback_finishs.push(callback_finish)

        //bundle配置加载
        await this.loadSubGameBundle(info, server_version)

        //加载场景
        if (info.state == SubGameBundleState.UPDATE_SCENE) {
            info.bundle.loadScene('GameScene' + gameId, {},
                (loaded: number, total: number) => {
                    let percent = (loaded / total) * 100;
                    if (percent > info.percent)
                        info.percent = percent
                    info.callback_updates.forEach(callback => callback(gameId, info.percent))
                    console.log(`已经下载资源数："${loaded}  总资源数：${total}  percent:${info.percent}`);
                },
                (err: Error, scene: SceneAsset) => {
                    if (!err) {
                        info.state = SubGameBundleState.NONE
                        this.setLocalVersion(gameId, server_version)
                        info.callback_finishs.forEach(callback => callback(gameId, scene))
                    }
                    else {
                        info.state = SubGameBundleState.UPDATE_SCENE_FAIL
                        console.error("load gameScene error:", err);
                    }
                    info.callback_updates.length = 0;
                    info.callback_finishs.length = 0;
                })
        }
    }
}
/**
 * 子游戏加载管理
 */
export const subMgr: SubMgr = SubMgr.getInstance<SubMgr>();



